Let us set some global options for all code chunks in this document.

# Set seed for reproducibility
set.seed(1982) 
# Set global options for all code chunks
knitr::opts_chunk$set(
  # Disable messages printed by R code chunks
  message = FALSE,    
  # Disable warnings printed by R code chunks
  warning = FALSE,    
  # Show R code within code chunks in output
  echo = TRUE,        
  # Include both R code and its results in output
  include = TRUE,     
  # Evaluate R code chunks
  eval = TRUE,       
  # Enable caching of R code chunks for faster rendering
  cache = FALSE,      
  # Align figures in the center of the output
  fig.align = "center",
  # Enable retina display for high-resolution figures
  retina = 2,
  # Show errors in the output instead of stopping rendering
  error = TRUE,
  # Do not collapse code and output into a single block
  collapse = FALSE
)
# inla.upgrade(testing = TRUE)
# remotes::install_github("inlabru-org/inlabru", ref = "devel")
# remotes::install_github("davidbolin/rspde", ref = "devel")
# remotes::install_github("davidbolin/metricgraph", ref = "devel")
library(INLA)
library(inlabru)
library(rSPDE)
library(MetricGraph)
library(grateful)

library(plotly)

We want to solve the fractional diffusion equation \[\begin{equation} \label{eq:maineq} \partial_t u+(\kappa^2-\Delta_\Gamma)^{\frac{\alpha}{2}} u=f \text { on } \Gamma \times(0, T), \quad u(0)=u_0 \text { on } \Gamma, \end{equation}\] where \(u\) satisfies the Kirchhoff vertex conditions \[\begin{equation} \label{eq:Kcond} \left\{\phi\in C(\Gamma)\;\Big|\; \forall v\in V: \sum_{e\in\mathcal{E}_v}\partial_e \phi(v)=0 \right\} \end{equation}\]

Let us start by building a graph.

graph <- metric_graph$new(perform_merges = TRUE, 
                          tolerance = list(edge_edge = 1e-3, 
                                           vertex_vertex = 1e-3, 
                                           edge_vertex = 1e-3))
graph$plot()

graph$build_mesh(h = 0.05)

Let \(\alpha\in(0,2]\) and \(U_h^\tau\) denote the sequence of approximations of the solution to the weak form of problem \(\eqref{eq:maineq}\) at each time step on a mesh indexed by \(h\). Let \(z=0\) and \(U^0_h = P_hu_0\). For \(k=0,\dots, N-1\), \(U_h^{k+1}\in V_h\) solves the following scheme \[\begin{align} \label{system:fully_discrete_scheme} \langle\delta U_h^{k+1},\phi\rangle + \mathfrak{a}(U_h^{k+1},\phi) = \langle f^{k+1},\phi\rangle ,\quad\forall\phi\in V_h, \end{align}\] where \(f^{k+1} = \displaystyle\dfrac{1}{\tau}\int_{t_k}^{t^{k+1}}f(t)dt\). The solution can be represented as \[\begin{align*} U_h^k(s) = \sum_{j=1}^{N_h}u_j^k\psi_j(s) \end{align*}\] Replacing this into \(\eqref{system:fully_discrete_scheme}\) yields the following linear system \[\begin{align*} \sum_{j=1}^{N_h}u_j^{k+1}[(\psi_j,\psi_i)_{L_2(\Gamma)}+ \tau\mathfrak{a}(\psi_j,\psi_i)] = \sum_{j=1}^{N_h}u_j^{k}(\psi_j,\psi_i)_{L_2(\Gamma)}+\tau( f^{k+1},\psi_i)_{L_2(\Gamma)} \end{align*}\] for \(i = 1,\dots, N_h\). In matrix notation, \[\begin{align} \label{diff_eq_discrete} (C+\tau A)U^{k+1} = CU^k+\tau F^{k+1}, \end{align}\] where \(C\) has entries \(C_{ij} = (\psi_j,\psi_i)_{L_2(\Gamma)}\), \(A\) has entries \(A_{ij} = \mathfrak{a}(\psi_j,\psi_i)\), \(U^k\) has entries \(u_j^k\), and \(F^k\) has entries \(( f^{k},\psi_i)_{L_2(\Gamma)}\). By multiplying both sides by \(A^{-1}\) and considering its operator-based rational approximation \(P_\ell^{-1}P_r\), we arrive at \((P_rC+\tau P_\ell)U^{k+1} = P_r(CU^k+\tau F^{k+1})\).

# Compute the FEM matrices
graph$compute_fem()
G <- graph$mesh$G
C <- graph$mesh$C
x <- graph$mesh$V[, 1]
y <- graph$mesh$V[, 2]
# Initial condition
U_0 <- 10*exp(-((x-4)^2 + (y-4)^2))
# Define the time step
time_step <- 0.1
# Define the right-hand side function
fun <- function(t) {return(sin(t)*((x-4)^2 - (y-4)^2))}
# Define the time discretization
time_seq <- seq(0,pi, by = time_step)
# Compute the right-hand side function at each time step
fun_mat <- do.call(cbind, lapply(time_seq, fun))
# Define the parameters
kappa <- 1
L <- kappa^2*C + G
alpha <- 0.8
beta <- alpha/2
op <- fractional.operators(L, beta, C, scale.factor = kappa^2, m = 1)
Pl <- op$Pl
Pr <- op$Pr
funF <- C %*% fun_mat 
# Precompute the LHS matrix
LHS <- Pr %*% C + time_step * Pl
# Initialize U matrix to store solution at each time step
U_mat <- matrix(NA, nrow = nrow(C), ncol = length(time_seq))
U_mat[, 1] <- U_0

# Time-stepping loop
for (k in 1:(length(time_seq) - 1)) {
  RHS <- Pr %*% (C %*% U_mat[, k] + time_step * funF[, k + 1])
  U_mat[, k + 1] <- as.matrix(solve(LHS, RHS))
}
# Plot the initial condition
p_ini <- graph$plot_function(X = U_0, 
                             vertex_size = 1, 
                             type = "plotly", 
                             edge_color = "black", 
                             edge_width = 3, 
                             line_color = "blue", 
                             line_width = 3)
p_ini
# Plot the movie of f
p_f <- graph$plot_movie(fun_mat)
p_f$x$layout$scene$xaxis$range <- range(x)
p_f$x$layout$scene$yaxis$range <- range(y)
p_f$x$layout$scene$zaxis$range <- range(fun_mat)
p_f
# Plot the movie of the solution
p_sol <- graph$plot_movie(U_mat)
p_sol$x$layout$scene$xaxis$range <- range(x)
p_sol$x$layout$scene$yaxis$range <- range(y)
p_sol$x$layout$scene$zaxis$range <- range(U_mat)
p_sol

References

cite_packages(output = "paragraph", out.dir = ".")

We used R version 4.4.3 (R Core Team 2025) and the following R packages: htmltools v. 0.5.8.1 (Cheng et al. 2024), INLA v. 25.4.16 (Rue, Martino, and Chopin 2009; Lindgren, Rue, and Lindström 2011; Martins et al. 2013; Lindgren and Rue 2015; De Coninck et al. 2016; Rue et al. 2017; Verbosio et al. 2017; Bakka et al. 2018; Kourounis, Fuchs, and Schenk 2018), inlabru v. 2.12.0.9012 (Yuan et al. 2017; Bachl et al. 2019), knitr v. 1.48 (Xie 2014, 2015, 2024), MetricGraph v. 1.4.1.9000 (Bolin, Simas, and Wallin 2023a, 2023b, 2024, 2025; Bolin et al. 2024), plotly v. 4.10.4 (Sievert 2020), rmarkdown v. 2.28 (Xie, Allaire, and Grolemund 2018; Xie, Dervieux, and Riederer 2020; Allaire et al. 2024), rSPDE v. 2.5.1.9000 (Bolin and Kirchner 2020; Bolin and Simas 2023; Bolin, Simas, and Xiong 2024), xaringanExtra v. 0.8.0 (Aden-Buie and Warkentin 2024).

Aden-Buie, Garrick, and Matthew T. Warkentin. 2024. xaringanExtra: Extras and Extensions for xaringan Slides. https://CRAN.R-project.org/package=xaringanExtra.
Allaire, JJ, Yihui Xie, Christophe Dervieux, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, et al. 2024. rmarkdown: Dynamic Documents for r. https://github.com/rstudio/rmarkdown.
Bachl, Fabian E., Finn Lindgren, David L. Borchers, and Janine B. Illian. 2019. inlabru: An R Package for Bayesian Spatial Modelling from Ecological Survey Data.” Methods in Ecology and Evolution 10: 760–66. https://doi.org/10.1111/2041-210X.13168.
Bakka, Haakon, Håvard Rue, Geir-Arne Fuglstad, Andrea I. Riebler, David Bolin, Janine Illian, Elias Krainski, Daniel P. Simpson, and Finn K. Lindgren. 2018. “Spatial Modelling with INLA: A Review.” WIRES (Invited Extended Review) xx (Feb): xx–. http://arxiv.org/abs/1802.06350.
Bolin, David, and Kristin Kirchner. 2020. “The Rational SPDE Approach for Gaussian Random Fields with General Smoothness.” Journal of Computational and Graphical Statistics 29 (2): 274–85. https://doi.org/10.1080/10618600.2019.1665537.
Bolin, David, Mihály Kovács, Vivek Kumar, and Alexandre B. Simas. 2024. “Regularity and Numerical Approximation of Fractional Elliptic Differential Equations on Compact Metric Graphs.” Mathematics of Computation 93 (349): 2439–72. https://doi.org/10.1090/mcom/3929.
Bolin, David, and Alexandre B. Simas. 2023. rSPDE: Rational Approximations of Fractional Stochastic Partial Differential Equations. https://CRAN.R-project.org/package=rSPDE.
Bolin, David, Alexandre B. Simas, and Jonas Wallin. 2023a. MetricGraph: Random Fields on Metric Graphs. https://CRAN.R-project.org/package=MetricGraph.
———. 2023b. “Statistical Inference for Gaussian Whittle-Matérn Fields on Metric Graphs.” arXiv Preprint arXiv:2304.10372. https://doi.org/10.48550/arXiv.2304.10372.
———. 2024. “Gaussian Whittle-Matérn Fields on Metric Graphs.” Bernoulli 30 (2): 1611–39. https://doi.org/10.3150/23-BEJ1647.
———. 2025. “Markov Properties of Gaussian Random Fields on Compact Metric Graphs.” Bernoulli. https://doi.org/10.48550/arXiv.2304.03190.
Bolin, David, Alexandre B. Simas, and Zhen Xiong. 2024. “Covariance-Based Rational Approximations of Fractional SPDEs for Computationally Efficient Bayesian Inference.” Journal of Computational and Graphical Statistics 33 (1): 64–74. https://doi.org/10.1080/10618600.2023.2231051.
Cheng, Joe, Carson Sievert, Barret Schloerke, Winston Chang, Yihui Xie, and Jeff Allen. 2024. htmltools: Tools for HTML. https://CRAN.R-project.org/package=htmltools.
De Coninck, Arne, Bernard De Baets, Drosos Kourounis, Fabio Verbosio, Olaf Schenk, Steven Maenhout, and Jan Fostier. 2016. Needles: Toward Large-Scale Genomic Prediction with Marker-by-Environment Interaction.” Genetics 203 (1): 543–55. https://doi.org/10.1534/genetics.115.179887.
Kourounis, D., A. Fuchs, and O. Schenk. 2018. “Towards the Next Generation of Multiperiod Optimal Power Flow Solvers.” IEEE Transactions on Power Systems PP (99): 1–10. https://doi.org/10.1109/TPWRS.2017.2789187.
Lindgren, Finn, and Håvard Rue. 2015. “Bayesian Spatial Modelling with R-INLA.” Journal of Statistical Software 63 (19): 1–25. http://www.jstatsoft.org/v63/i19/.
Lindgren, Finn, Håvard Rue, and Johan Lindström. 2011. “An Explicit Link Between Gaussian Fields and Gaussian Markov Random Fields: The Stochastic Partial Differential Equation Approach (with Discussion).” Journal of the Royal Statistical Society B 73 (4): 423–98.
Martins, Thiago G., Daniel Simpson, Finn Lindgren, and Håvard Rue. 2013. “Bayesian Computing with INLA: New Features.” Computational Statistics and Data Analysis 67: 68–83.
R Core Team. 2025. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Rue, Håvard, Sara Martino, and Nicholas Chopin. 2009. “Approximate Bayesian Inference for Latent Gaussian Models Using Integrated Nested Laplace Approximations (with Discussion).” Journal of the Royal Statistical Society B 71: 319–92.
Rue, Håvard, Andrea I. Riebler, Sigrunn H. Sørbye, Janine B. Illian, Daniel P. Simpson, and Finn K. Lindgren. 2017. “Bayesian Computing with INLA: A Review.” Annual Reviews of Statistics and Its Applications 4 (March): 395–421. http://arxiv.org/abs/1604.00860.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Verbosio, Fabio, Arne De Coninck, Drosos Kourounis, and Olaf Schenk. 2017. “Enhancing the Scalability of Selected Inversion Factorization Algorithms in Genomic Prediction.” Journal of Computational Science 22 (Supplement C): 99–108. https://doi.org/10.1016/j.jocs.2017.08.013.
Xie, Yihui. 2014. knitr: A Comprehensive Tool for Reproducible Research in R.” In Implementing Reproducible Computational Research, edited by Victoria Stodden, Friedrich Leisch, and Roger D. Peng. Chapman; Hall/CRC.
———. 2015. Dynamic Documents with R and Knitr. 2nd ed. Boca Raton, Florida: Chapman; Hall/CRC. https://yihui.org/knitr/.
———. 2024. knitr: A General-Purpose Package for Dynamic Report Generation in r. https://yihui.org/knitr/.
Xie, Yihui, J. J. Allaire, and Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown.
Xie, Yihui, Christophe Dervieux, and Emily Riederer. 2020. R Markdown Cookbook. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown-cookbook.
Yuan, Yuan, Bachl, Fabian E., Lindgren, Finn, Borchers, et al. 2017. “Point Process Models for Spatio-Temporal Distance Sampling Data from a Large-Scale Survey of Blue Whales.” Ann. Appl. Stat. 11 (4): 2270–97. https://doi.org/10.1214/17-AOAS1078.
LS0tCnRpdGxlOiAiU29sdmluZyBhIHBhcmFib2xpYyBlcXVhdGlvbiIKZGF0ZTogIkNyZWF0ZWQ6IDIwLTA0LTIwMjUuIExhc3QgbW9kaWZpZWQ6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVkuJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG1hdGhqYXg6ICJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL21hdGhqYXhAMy9lczUvdGV4LW1tbC1jaHRtbC5qcyIKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZm9sZGluZzogc2hvdyAjIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiIHRvIGhpZGUgY29kZSBhbmQgYWRkIGEgYnV0dG9uIHRvIHNob3cgaXQKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQpiaWJsaW9ncmFwaHk6IAogIC0gcmVmZXJlbmNlcy5iaWIKICAtIGdyYXRlZnVsLXJlZnMuYmliCmhlYWRlci1pbmNsdWRlczoKICAtIFxuZXdjb21tYW5ke1xhcn17XG1hdGhiYntSfX0KICAtIFxuZXdjb21tYW5ke1xsbGF2fVsxXXtcbGVmdFx7IzFccmlnaHRcfX0KICAtIFxuZXdjb21tYW5ke1xwYXJlfVsxXXtcbGVmdCgjMVxyaWdodCl9CiAgLSBcbmV3Y29tbWFuZHtcTmNhbH17XG1hdGhjYWx7Tn19CiAgLSBcbmV3Y29tbWFuZHtcVmNhbH17XG1hdGhjYWx7Vn19CiAgLSBcbmV3Y29tbWFuZHtcRWNhbH17XG1hdGhjYWx7RX19CiAgLSBcbmV3Y29tbWFuZHtcV2NhbH17XG1hdGhjYWx7V319Ci0tLQoKYGBge3IgeGFyaW5nYW5FeHRyYS1jbGlwYm9hcmQsIGVjaG8gPSBGQUxTRX0KaHRtbHRvb2xzOjp0YWdMaXN0KAogIHhhcmluZ2FuRXh0cmE6OnVzZV9jbGlwYm9hcmQoCiAgICBidXR0b25fdGV4dCA9ICI8aSBjbGFzcz1cImZhLXNvbGlkIGZhLWNsaXBib2FyZFwiIHN0eWxlPVwiY29sb3I6ICMwMDAwOEJcIj48L2k+IiwKICAgIHN1Y2Nlc3NfdGV4dCA9ICI8aSBjbGFzcz1cImZhIGZhLWNoZWNrXCIgc3R5bGU9XCJjb2xvcjogIzkwQkU2RFwiPjwvaT4iLAogICAgZXJyb3JfdGV4dCA9ICI8aSBjbGFzcz1cImZhIGZhLXRpbWVzLWNpcmNsZVwiIHN0eWxlPVwiY29sb3I6ICNGOTQxNDRcIj48L2k+IgogICksCiAgcm1hcmtkb3duOjpodG1sX2RlcGVuZGVuY3lfZm9udF9hd2Vzb21lKCkKKQpgYGAKCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmJvZHkgLm1haW4tY29udGFpbmVyIHsKICBtYXgtd2lkdGg6IDEwMCUgIWltcG9ydGFudDsKICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Owp9CmJvZHkgewogIG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50Owp9Cgpib2R5LCB0ZCB7CiAgIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNHB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNHB4Cn0KLmN1c3RvbS1ib3ggewogIGJhY2tncm91bmQtY29sb3I6ICNmNWY3ZmE7IC8qIExpZ2h0IGdyZXktYmx1ZSBiYWNrZ3JvdW5kICovCiAgYm9yZGVyLWNvbG9yOiAjZTFlOGVkOyAvKiBMaWdodCBib3JkZXIgY29sb3IgKi8KICBjb2xvcjogIzJjM2U1MDsgLyogRGFyayB0ZXh0IGNvbG9yICovCiAgcGFkZGluZzogMTVweDsgLyogUGFkZGluZyBpbnNpZGUgdGhlIGJveCAqLwogIGJvcmRlci1yYWRpdXM6IDVweDsgLyogUm91bmRlZCBjb3JuZXJzICovCiAgbWFyZ2luLWJvdHRvbTogMjBweDsgLyogU3BhY2luZyBiZWxvdyB0aGUgYm94ICovCn0KLmNhcHRpb24gewogIG1hcmdpbjogYXV0bzsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgbWFyZ2luLWJvdHRvbTogMjBweDsgLyogU3BhY2luZyBiZWxvdyB0aGUgYm94ICovCn0KYGBgCgoKTGV0IHVzIHNldCBzb21lIGdsb2JhbCBvcHRpb25zIGZvciBhbGwgY29kZSBjaHVua3MgaW4gdGhpcyBkb2N1bWVudC4KCgpgYGB7cn0KIyBTZXQgc2VlZCBmb3IgcmVwcm9kdWNpYmlsaXR5CnNldC5zZWVkKDE5ODIpIAojIFNldCBnbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAjIERpc2FibGUgbWVzc2FnZXMgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAKICAjIERpc2FibGUgd2FybmluZ3MgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAKICAjIFNob3cgUiBjb2RlIHdpdGhpbiBjb2RlIGNodW5rcyBpbiBvdXRwdXQKICBlY2hvID0gVFJVRSwgICAgICAgIAogICMgSW5jbHVkZSBib3RoIFIgY29kZSBhbmQgaXRzIHJlc3VsdHMgaW4gb3V0cHV0CiAgaW5jbHVkZSA9IFRSVUUsICAgICAKICAjIEV2YWx1YXRlIFIgY29kZSBjaHVua3MKICBldmFsID0gVFJVRSwgICAgICAgCiAgIyBFbmFibGUgY2FjaGluZyBvZiBSIGNvZGUgY2h1bmtzIGZvciBmYXN0ZXIgcmVuZGVyaW5nCiAgY2FjaGUgPSBGQUxTRSwgICAgICAKICAjIEFsaWduIGZpZ3VyZXMgaW4gdGhlIGNlbnRlciBvZiB0aGUgb3V0cHV0CiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgIyBFbmFibGUgcmV0aW5hIGRpc3BsYXkgZm9yIGhpZ2gtcmVzb2x1dGlvbiBmaWd1cmVzCiAgcmV0aW5hID0gMiwKICAjIFNob3cgZXJyb3JzIGluIHRoZSBvdXRwdXQgaW5zdGVhZCBvZiBzdG9wcGluZyByZW5kZXJpbmcKICBlcnJvciA9IFRSVUUsCiAgIyBEbyBub3QgY29sbGFwc2UgY29kZSBhbmQgb3V0cHV0IGludG8gYSBzaW5nbGUgYmxvY2sKICBjb2xsYXBzZSA9IEZBTFNFCikKYGBgCgoKCgpgYGB7cn0KIyBpbmxhLnVwZ3JhZGUodGVzdGluZyA9IFRSVUUpCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImlubGFicnUtb3JnL2lubGFicnUiLCByZWYgPSAiZGV2ZWwiKQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJkYXZpZGJvbGluL3JzcGRlIiwgcmVmID0gImRldmVsIikKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGF2aWRib2xpbi9tZXRyaWNncmFwaCIsIHJlZiA9ICJkZXZlbCIpCmxpYnJhcnkoSU5MQSkKbGlicmFyeShpbmxhYnJ1KQpsaWJyYXJ5KHJTUERFKQpsaWJyYXJ5KE1ldHJpY0dyYXBoKQpsaWJyYXJ5KGdyYXRlZnVsKQoKbGlicmFyeShwbG90bHkpCmBgYAoKCldlIHdhbnQgdG8gc29sdmUgdGhlIGZyYWN0aW9uYWwgZGlmZnVzaW9uIGVxdWF0aW9uClxiZWdpbntlcXVhdGlvbn0KXGxhYmVse2VxOm1haW5lcX0KICAgIFxwYXJ0aWFsX3QgdSsoXGthcHBhXjItXERlbHRhX1xHYW1tYSlee1xmcmFje1xhbHBoYX17Mn19IHU9ZiBcdGV4dCB7IG9uIH0gXEdhbW1hIFx0aW1lcygwLCBUKSwgXHF1YWQgdSgwKT11XzAgXHRleHQgeyBvbiB9IFxHYW1tYSwKXGVuZHtlcXVhdGlvbn0Kd2hlcmUgJHUkIHNhdGlzZmllcyB0aGUgS2lyY2hob2ZmIHZlcnRleCBjb25kaXRpb25zClxiZWdpbntlcXVhdGlvbn0KXGxhYmVse2VxOktjb25kfQogICAgXGxlZnRce1xwaGlcaW4gQyhcR2FtbWEpXDtcQmlnfFw7IFxmb3JhbGwgdlxpbiBWOiBcc3VtX3tlXGluXG1hdGhjYWx7RX1fdn1ccGFydGlhbF9lIFxwaGkodik9MCBccmlnaHRcfQpcZW5ke2VxdWF0aW9ufQoKTGV0IHVzIHN0YXJ0IGJ5IGJ1aWxkaW5nIGEgZ3JhcGguCgpgYGB7cn0KZ3JhcGggPC0gbWV0cmljX2dyYXBoJG5ldyhwZXJmb3JtX21lcmdlcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHRvbGVyYW5jZSA9IGxpc3QoZWRnZV9lZGdlID0gMWUtMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJ0ZXhfdmVydGV4ID0gMWUtMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlX3ZlcnRleCA9IDFlLTMpKQpncmFwaCRwbG90KCkKZ3JhcGgkYnVpbGRfbWVzaChoID0gMC4wNSkKYGBgCgpMZXQgJFxhbHBoYVxpbigwLDJdJCBhbmQgJFVfaF5cdGF1JCBkZW5vdGUgdGhlIHNlcXVlbmNlIG9mIGFwcHJveGltYXRpb25zIG9mIHRoZSBzb2x1dGlvbiB0byB0aGUgd2VhayBmb3JtIG9mIHByb2JsZW0gXGVxcmVme2VxOm1haW5lcX0gYXQgZWFjaCB0aW1lIHN0ZXAgb24gYSBtZXNoIGluZGV4ZWQgYnkgJGgkLiBMZXQgJHo9MCQgYW5kICRVXjBfaCA9IFBfaHVfMCQuIEZvciAkaz0wLFxkb3RzLCBOLTEkLCAkVV9oXntrKzF9XGluIFZfaCQgc29sdmVzIHRoZSBmb2xsb3dpbmcgc2NoZW1lClxiZWdpbnthbGlnbn0KXGxhYmVse3N5c3RlbTpmdWxseV9kaXNjcmV0ZV9zY2hlbWV9CiAgICAgICAgXGxhbmdsZVxkZWx0YSBVX2hee2srMX0sXHBoaVxyYW5nbGUgKyBcbWF0aGZyYWt7YX0oVV9oXntrKzF9LFxwaGkpID0gXGxhbmdsZSBmXntrKzF9LFxwaGlccmFuZ2xlICxccXVhZFxmb3JhbGxccGhpXGluIFZfaCwKXGVuZHthbGlnbn0Kd2hlcmUgJGZee2srMX0gPSBcZGlzcGxheXN0eWxlXGRmcmFjezF9e1x0YXV9XGludF97dF9rfV57dF57aysxfX1mKHQpZHQkLgpUaGUgc29sdXRpb24gY2FuIGJlIHJlcHJlc2VudGVkIGFzIApcYmVnaW57YWxpZ24qfQogICAgVV9oXmsocykgPSAgXHN1bV97aj0xfV57Tl9ofXVfal5rXHBzaV9qKHMpClxlbmR7YWxpZ24qfQpSZXBsYWNpbmcgdGhpcyBpbnRvIFxlcXJlZntzeXN0ZW06ZnVsbHlfZGlzY3JldGVfc2NoZW1lfSB5aWVsZHMgdGhlIGZvbGxvd2luZyBsaW5lYXIgc3lzdGVtClxiZWdpbnthbGlnbip9CiAgICBcc3VtX3tqPTF9XntOX2h9dV9qXntrKzF9WyhccHNpX2osXHBzaV9pKV97TF8yKFxHYW1tYSl9KyBcdGF1XG1hdGhmcmFre2F9KFxwc2lfaixccHNpX2kpXSA9IFxzdW1fe2o9MX1ee05faH11X2pee2t9KFxwc2lfaixccHNpX2kpX3tMXzIoXEdhbW1hKX0rXHRhdSggZl57aysxfSxccHNpX2kpX3tMXzIoXEdhbW1hKX0KXGVuZHthbGlnbip9CmZvciAkaSA9IDEsXGRvdHMsIE5faCQuIEluIG1hdHJpeCBub3RhdGlvbiwKXGJlZ2lue2FsaWdufQpcbGFiZWx7ZGlmZl9lcV9kaXNjcmV0ZX0KICAgIChDK1x0YXUgQSlVXntrKzF9ID0gQ1VeaytcdGF1IEZee2srMX0sClxlbmR7YWxpZ259CndoZXJlICRDJCBoYXMgZW50cmllcyAkQ197aWp9ID0gKFxwc2lfaixccHNpX2kpX3tMXzIoXEdhbW1hKX0kLCAkQSQgaGFzIGVudHJpZXMgJEFfe2lqfSA9IFxtYXRoZnJha3thfShccHNpX2osXHBzaV9pKSQsICRVXmskIGhhcyBlbnRyaWVzICR1X2peayQsIGFuZCAkRl5rJCBoYXMgZW50cmllcyAkKCBmXntrfSxccHNpX2kpX3tMXzIoXEdhbW1hKX0kLiBCeSBtdWx0aXBseWluZyBib3RoIHNpZGVzIGJ5ICRBXnstMX0kIGFuZCBjb25zaWRlcmluZyBpdHMgb3BlcmF0b3ItYmFzZWQgcmF0aW9uYWwgYXBwcm94aW1hdGlvbiAkUF9cZWxsXnstMX1QX3IkLCB3ZSBhcnJpdmUgYXQgJChQX3JDK1x0YXUgUF9cZWxsKVVee2srMX0gPSBQX3IoQ1VeaytcdGF1IEZee2srMX0pJC4KCmBgYHtyfQojIENvbXB1dGUgdGhlIEZFTSBtYXRyaWNlcwpncmFwaCRjb21wdXRlX2ZlbSgpCkcgPC0gZ3JhcGgkbWVzaCRHCkMgPC0gZ3JhcGgkbWVzaCRDCnggPC0gZ3JhcGgkbWVzaCRWWywgMV0KeSA8LSBncmFwaCRtZXNoJFZbLCAyXQojIEluaXRpYWwgY29uZGl0aW9uClVfMCA8LSAxMCpleHAoLSgoeC00KV4yICsgKHktNCleMikpCiMgRGVmaW5lIHRoZSB0aW1lIHN0ZXAKdGltZV9zdGVwIDwtIDAuMQojIERlZmluZSB0aGUgcmlnaHQtaGFuZCBzaWRlIGZ1bmN0aW9uCmZ1biA8LSBmdW5jdGlvbih0KSB7cmV0dXJuKHNpbih0KSooKHgtNCleMiAtICh5LTQpXjIpKX0KIyBEZWZpbmUgdGhlIHRpbWUgZGlzY3JldGl6YXRpb24KdGltZV9zZXEgPC0gc2VxKDAscGksIGJ5ID0gdGltZV9zdGVwKQojIENvbXB1dGUgdGhlIHJpZ2h0LWhhbmQgc2lkZSBmdW5jdGlvbiBhdCBlYWNoIHRpbWUgc3RlcApmdW5fbWF0IDwtIGRvLmNhbGwoY2JpbmQsIGxhcHBseSh0aW1lX3NlcSwgZnVuKSkKIyBEZWZpbmUgdGhlIHBhcmFtZXRlcnMKa2FwcGEgPC0gMQpMIDwtIGthcHBhXjIqQyArIEcKYWxwaGEgPC0gMC44CmJldGEgPC0gYWxwaGEvMgpvcCA8LSBmcmFjdGlvbmFsLm9wZXJhdG9ycyhMLCBiZXRhLCBDLCBzY2FsZS5mYWN0b3IgPSBrYXBwYV4yLCBtID0gMSkKUGwgPC0gb3AkUGwKUHIgPC0gb3AkUHIKZnVuRiA8LSBDICUqJSBmdW5fbWF0IApgYGAKCgpgYGB7cn0KIyBQcmVjb21wdXRlIHRoZSBMSFMgbWF0cml4CkxIUyA8LSBQciAlKiUgQyArIHRpbWVfc3RlcCAqIFBsCiMgSW5pdGlhbGl6ZSBVIG1hdHJpeCB0byBzdG9yZSBzb2x1dGlvbiBhdCBlYWNoIHRpbWUgc3RlcApVX21hdCA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KEMpLCBuY29sID0gbGVuZ3RoKHRpbWVfc2VxKSkKVV9tYXRbLCAxXSA8LSBVXzAKCiMgVGltZS1zdGVwcGluZyBsb29wCmZvciAoayBpbiAxOihsZW5ndGgodGltZV9zZXEpIC0gMSkpIHsKICBSSFMgPC0gUHIgJSolIChDICUqJSBVX21hdFssIGtdICsgdGltZV9zdGVwICogZnVuRlssIGsgKyAxXSkKICBVX21hdFssIGsgKyAxXSA8LSBhcy5tYXRyaXgoc29sdmUoTEhTLCBSSFMpKQp9CmBgYAoKCmBgYHtyfQojIFBsb3QgdGhlIGluaXRpYWwgY29uZGl0aW9uCnBfaW5pIDwtIGdyYXBoJHBsb3RfZnVuY3Rpb24oWCA9IFVfMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVydGV4X3NpemUgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkZ2VfY29sb3IgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlX3dpZHRoID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZV9jb2xvciA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZV93aWR0aCA9IDMpCnBfaW5pCiMgUGxvdCB0aGUgbW92aWUgb2YgZgpwX2YgPC0gZ3JhcGgkcGxvdF9tb3ZpZShmdW5fbWF0KQpwX2YkeCRsYXlvdXQkc2NlbmUkeGF4aXMkcmFuZ2UgPC0gcmFuZ2UoeCkKcF9mJHgkbGF5b3V0JHNjZW5lJHlheGlzJHJhbmdlIDwtIHJhbmdlKHkpCnBfZiR4JGxheW91dCRzY2VuZSR6YXhpcyRyYW5nZSA8LSByYW5nZShmdW5fbWF0KQpwX2YKIyBQbG90IHRoZSBtb3ZpZSBvZiB0aGUgc29sdXRpb24KcF9zb2wgPC0gZ3JhcGgkcGxvdF9tb3ZpZShVX21hdCkKcF9zb2wkeCRsYXlvdXQkc2NlbmUkeGF4aXMkcmFuZ2UgPC0gcmFuZ2UoeCkKcF9zb2wkeCRsYXlvdXQkc2NlbmUkeWF4aXMkcmFuZ2UgPC0gcmFuZ2UoeSkKcF9zb2wkeCRsYXlvdXQkc2NlbmUkemF4aXMkcmFuZ2UgPC0gcmFuZ2UoVV9tYXQpCnBfc29sCmBgYAoKCgojIFJlZmVyZW5jZXMKCmBgYHtyfQpjaXRlX3BhY2thZ2VzKG91dHB1dCA9ICJwYXJhZ3JhcGgiLCBvdXQuZGlyID0gIi4iKQpgYGAK